/*
 * Copyright (c) 2015, FPX and/or its affiliates. All rights reserved.
 * Use, Copy is subject to authorized license.
 */
package org.linetime.netty.chapter01;

import io.netty.bootstrap.Bootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.string.StringEncoder;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

/**
 * @author sangaiz
 * @date 2019/8/14
 * @since v1.0.0
 */

public class NettyClient {

    /**
     * 最大重试次数
     */
    private static final int MAX_RETRY = 5;

    public static void main(String[] args) throws InterruptedException {
        // 客户端启动引导类，负责启动客户端以及连接服务端
        Bootstrap bootstrap = new Bootstrap();

        NioEventLoopGroup group = new NioEventLoopGroup();
        // 确定线程模型
        bootstrap.group(group)
                // 设置IO模型
                .channel(NioSocketChannel.class)
                // 定义连接的业务处理逻辑
                .handler(new ChannelInitializer<Channel>() {
                    @Override
                    protected void initChannel(Channel ch) {
                        ch.pipeline().addLast(new StringEncoder());
                    }
                });
        // 连接服务端，可重试
        Channel channel = connect(bootstrap, "127.0.0.1", 8000, 1).channel();

        int i = 0;
        do {
            // 向服务端写数据
            channel.writeAndFlush(LocalDateTime.now() + ": hello world!");
            Thread.sleep(2000);
            ++i;
        } while (i < 3);

    }

    /**
     * 连接服务端，有重试的功能
     * @param bootstrap 客户端引导类
     * @param host 服务端主机
     * @param port 服务端端口
     * @param retry 连接次数
     * @return 连接结果
     */
    private static ChannelFuture connect(Bootstrap bootstrap, String host, int port, int retry) {
        System.out.println("第"+retry+"次连接进行中...");
        return bootstrap.connect(host, port).addListener(future -> {
            if (future.isSuccess()) {
                System.out.println("连接成功");
            } else {
                // 重连次数
                int order = retry + 1;
                int delay = 1 << retry;

                if (order <= MAX_RETRY) {
                    System.err.println("第" + retry + "次连接失败，在"+delay+"秒后开始第" + order + "次重连");
                    bootstrap.config().group().schedule(() -> connect(bootstrap, host, port, order), delay, TimeUnit.SECONDS);
                } else {
                    System.err.println("第" + retry + "次连接失败,2秒后退出");
                    Thread.sleep(2000);
                    System.out.println("退出");
                    System.exit(0);
                }
            }
        });
    }
}
